//
//  AMSimilarityManager.swift
//  YCCamera
//
//  Created by Billy on 2024/5/16.
//

import Photos
import Vision
import UIKit

class AMSimilarityManager: NSObject {
    
    // 三小时（单位：秒）, 间隔三小时的元素才需要比对
    static let maxTimeGap: TimeInterval = 3600 * 3
    
    static let imageSize: CGSize = CGSize(width: 100, height: 100)
    
    public class func similarityGroup(_ assets: [PHAsset]) -> [PHAsset] {
        var inputAssets = assets
        var outputGroups = [PHAsset]()
        var i = 0
        
        while i < inputAssets.count {
            autoreleasepool {
                // 取出代表的元素
                let representObject = inputAssets[i]
                // 将代表元素放入
                var disGroups: [PHAsset] = [representObject]
                
                var j = i + 1
                
                autoreleasepool {
                    // 内层循环，从代表对象的下一个元素开始比较
                    while j < inputAssets.count {
                        
                        // 取出要比对的元素
                        let candidate = inputAssets[j]
                        
                        if judgeTime(representObject, candidate) {
                            judge(representObject, candidate) { Bool in
                                if Bool {
                                    disGroups.append(candidate)
                                }
                            }
                            // 继续，指向下一位
                            j += 1
                        } else {
                            // 如果时间间隔不符合，则跳出内层循环
                            break
                        }
                    }
                }
                
                if disGroups.count > 1 {
                    for asset in disGroups {
                        if let index = inputAssets.firstIndex(of: asset) {
                            inputAssets.remove(at: index)
                        }
                    }
                    outputGroups.append(contentsOf: disGroups)
                } else {
                    i += 1
                }
            }
        }
        return outputGroups
    }
    
    // 图片相似度判断方法
    public class func judge(_ representative: PHAsset, _ candidate: PHAsset, completion: @escaping (Bool) -> Void)  {
        
        print("-------开始对比")
        
        var representFeaturePrint: VNFeaturePrintObservation?
        var candidateFeaturePrint: VNFeaturePrintObservation?
        
        guard let representImage = AMPhotoManager.syncRequestImage(asset: representative, targetSize: imageSize) else { completion(false); return }
        // 获取代表图特征值
        representFeaturePrint = extractFeaturePrint(from: representImage)
        
        guard let candidateImage = AMPhotoManager.syncRequestImage(asset: candidate, targetSize: imageSize) else { completion(false); return }
        // 获取对比图特征值
        candidateFeaturePrint = extractFeaturePrint(from: candidateImage)
        
        
        guard let representFeaturePrint = representFeaturePrint, let candidateFeaturePrint = candidateFeaturePrint else {
            
            print("........获取代表图特征值")
            completion(false)
            return
        }
        
        // 比较两个特征描述符的相似度
        if let distance = compareFeaturePrints(representFeaturePrint, candidateFeaturePrint) {
            // 设置一个阈值，距离小于阈值的图片认为是相似的
            let threshold: Float = 0.5
            let isSimilar = distance < threshold
            print("----------结束对比")
            completion(isSimilar)
        } else {
            print("----------对比失败")
            completion(false)
        }
    }
    
    // 提取图像的特征描述符
    public class func extractFeaturePrint(from image: UIImage) -> VNFeaturePrintObservation? {
        
        guard let cgImage = image.cgImage else {
            return nil
        }
        print("～～～～～～～～开始提取特征")
        let requestHandler = VNImageRequestHandler(cgImage: cgImage, options: [:])
        let request = VNGenerateImageFeaturePrintRequest()
        
        // 获取一个全局并发队列，并指定其QoS级别为.userInitiated，表示这些任务是用户明确请求的，并且期望快速完成
//        DispatchQueue.global(qos: .userInitiated).async {
            do {
                try requestHandler.perform([request])
                return request.results?.first as? VNFeaturePrintObservation
            } catch {
                print("Failed to perform feature print request: \(error)")
                return nil
            }
//        }
    }
    
    // 比较两个图像的特征描述符
    public class func compareFeaturePrints(_ fp1: VNFeaturePrintObservation, _ fp2: VNFeaturePrintObservation) -> Float? {
        var distance = Float(0)
        do {
            try fp1.computeDistance(&distance, to: fp2)
            return distance
        } catch {
            print("Failed to compute distance: \(error)")
            return nil
        }
    }
    
    public class func judgeTime(_ representative: PHAsset, _ candidate: PHAsset) -> Bool {
        guard let repDate = representative.creationDate, let canDate = candidate.creationDate else {
            return false
        }
        return abs(repDate.timeIntervalSince1970 - canDate.timeIntervalSince1970) <= maxTimeGap
    }
}
